package org.lexapp.ftp
{
	import com.carlcalderon.arthropod.Debug;
	
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.utils.getTimer;
	
	import pl.maliboo.ftp.core.FTPClient;
	import pl.maliboo.ftp.events.FTPEvent;
	import pl.maliboo.ftp.invokers.UploadInv;
	
	import org.lexapp.ftp.UploaderEvent;
//	import .model.MetaData;

	/**
	 * This class overrides the FTPClient of malibu
	 * It is specilized for uploads only
	 * - connects, login and start upload in one method call
	 * - handles the restore mode to restart the upload of a partially uploaded file
	 */
	public class UploaderClient extends FTPClient
	{
		////////////////////////////////////////////////////////
		// Group: state names in the cell renderer
		////////////////////////////////////////////////////////
		
		public static var STATE_VIDEO_UPLOADING_EMPTY_XML:String="STATE_VIDEO_UPLOADING_EMPTY_XML";
		public static var STATE_VIDEO_UPLOADING:String="STATE_VIDEO_UPLOADING";
		public static var STATE_VIDEO_WAITING_XML:String="STATE_VIDEO_WAITING_XML";
		public static var STATE_VIDEO_UPLOADING_XML:String="STATE_VIDEO_UPLOADING_XML";
		public static var STATE_VIDEO_CANCEL:String="STATE_VIDEO_CANCEL";
		public static var STATE_VIDEO_UPLOAD_SUCCESS:String="STATE_VIDEO_UPLOAD_SUCCESS";
		public static var STATE_VIDEO_UPLOADING_PREVIEW:String="STATE_VIDEO_UPLOADING_PREVIEW";
		
		////////////////////////////////////////////////////////
		// Group: attributes for the RemoteFileBrowser class
		////////////////////////////////////////////////////////
		/**
		 * metadata entered by the user
		 * used in the SingleVideoMetadataEditor form
		 */
//		public var metaData:MetaData=new MetaData;
		/**
		 * ID of the chaptered video 
		 * For chaptered video videos only 
		 */
/*		in metaData
		[Bindable]
		public var chapterId:String;
		/**
		 * ID of a chapter of the chaptered video 
		 * For chaptered video videos only 
		 */
/*		in metaData
		[Bindable]
		public var uploaderId:String;
		
		/**
		 * path of the source file on local computer
		 */
		public var srcPath:String;
		/**
		 * destination file name
		 */
		public var destName:String;
		/**
		 * destination folder
		 */
		public var destFolder:String;
		/**
		 * XML file name corresponding to the destName
		 * "my_media.xxx" becomes "my_media.xml" 
		 */
		public var xmlFileName:String;
		/**
		 * time at which upload has started
		 */
		public var uploadStartTime:int;
		/**
		 * size of the local file
		 */
		public var fileSize:uint;
		/**
		 * progress state for the cell renderer
		 * used by the cell renderer
		 */
		public var bytesLoaded:uint = 0;
		/**
		 * state of the upload
		 * used by the cell renderer
		 */
		public var _state:String=STATE_VIDEO_UPLOADING;
		public function get state():String
		{
			return _state;
		}
		public function set state(val:String):void
		{
			_state = val;
			dispatchEvent(new Event(UploaderEvent.STATE_CHANGED));
		}

		////////////////////////////////////////////////////////
		// Group: methods
		////////////////////////////////////////////////////////
		/**
		 * Constructor
		 */				
		public function UploaderClient(host:String="", port:int=21)
		{
			super(host, port);
		}
		/**
		 * upload an empty xml file
		 */
		public function putEmptyFile (remoteFile:String):void
		{
			Debug.log("UploaderClient - putEmptyFile "+remoteFile);
			trace("putEmptyFile: "+remoteFile)
			invoke(new UploadInv(this, null, remoteFile));
		}
		/**
		 * allow edition of the metafata if the upload did not occure yet
		 */
/*		public function isMetaDataEditionAlowed():Boolean
		{
			return (state == STATE_VIDEO_WAITING_XML 
				|| state == STATE_VIDEO_UPLOADING 
				|| state == STATE_VIDEO_UPLOADING_EMPTY_XML)
		}
*/		/**
		 * start the connection process
		 */				
		public function loginAndUpload(userLogin:String,userPass:String,srcPath:String,destFolder:String,destName:String,fileSize:uint):void
		{
			Debug.log("UploaderClient - loginAndUpload  ");
			
			// store data
			this.srcPath = srcPath;
			this.destName = destName;
			this.destFolder = destFolder;
			this.fileSize = fileSize;
			user = userLogin;
			pass=userPass;
			
			// compute the xml file name - "my_media.xxx" becomes "my_media.xml"
			xmlFileName = destName.substring(0,destName.lastIndexOf(".")) + ".xml";
               
			// connect
			addEventListener(FTPEvent.CONNECTED,doLoginAfterConnected);
			connect(host,port);
			
			// update state
			state = STATE_VIDEO_UPLOADING_EMPTY_XML;
		}
		/**
		 * start the login process
		 */
		private function doLoginAfterConnected(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - doLoginAfterConnected "+user);
			removeEventListener(FTPEvent.CONNECTED,doLoginAfterConnected);
			addEventListener(FTPEvent.LOGGED,doXMLUploadAfterLogin);
			login(user,pass);
		}
		/**
		 * start the upload process
		 * => upload an empty xml file
		 */
		private function doXMLUploadAfterLogin(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - doXMLUploadAfterLogin "+e);
			removeEventListener(FTPEvent.LOGGED,doXMLUploadAfterLogin);
			addEventListener(FTPEvent.UPLOAD,doUploadAfterLogin);
			
			putEmptyFile(destFolder+xmlFileName);
		}
		/**
		 * start the upload process
		 * => upload an empty xml file
		 */
		private function doUploadAfterLogin(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - doUploadAfterLogin "+e);
			removeEventListener(FTPEvent.UPLOAD,doUploadAfterLogin);
			addEventListener(FTPEvent.UPLOAD,handleUploadFinished);
			addEventListener(FTPEvent.LISTING, checkUploadFinished);
			putFile(srcPath,destFolder+destName);
			uploadStartTime = getTimer();
			
			// update state
			state = STATE_VIDEO_UPLOADING;
		}
		/**
		 * partial upload has finished
		 * => list to check the file size on the server
		 */
		protected function handleUploadFinished(event:FTPEvent):void
		{
			Debug.log("handleUploadFinished ",Debug.BLUE);
			list(destFolder);
		}
		/**
		 * Check if the upload is finished or if it has to be restored
		 * Called when the upload process disconnects
		 * Restore the upload or dispatch upload done event
		 */
		private function checkUploadFinished(event:FTPEvent):void 
		{
			Debug.log("checkUploadFinished "+event.listing.length+" - "+fileSize,Debug.BLUE);
			for (var idx:int=0;idx<event.listing.length;idx++)
			{
				Debug.log("checkUploadFinished Client Listing "+event.listing[idx].name+" =?= "+destName,Debug.BLUE);
				if (destName == event.listing[idx].name)
				{
					Debug.log("checkUploadFinished - allready uploaded: "+event.listing[idx].size+" / "+fileSize,Debug.BLUE);
					
					if (event.listing[idx].size >= fileSize)
					{
						Debug.log("checkUploadFinished - upload Done",Debug.BLUE);
						
						removeEventListener(FTPEvent.LISTING,checkUploadFinished);
						removeEventListener(FTPEvent.UPLOAD,handleUploadFinished);

						// Dispatching upload done
						var downloadEvent:FTPEvent = new FTPEvent(FTPEvent.UPLOAD_REAL_END);
						downloadEvent.bytesTotal = event.listing[idx].size;
						downloadEvent.file = destFolder+destName;
						downloadEvent.time = getTimer() - uploadStartTime;
						dispatchEvent(downloadEvent);

//						if (metaData && metaData.foldername)
						{
							// upload the preview (xml and then jpg), and after that, upload the metadata
							completeUpload();
						}
/*						else
						{
							// wait for meta data to upload							
							// update state
							state = STATE_VIDEO_WAITING_XML;
						}
*/
					}
					else
					{
						Debug.log("checkUploadFinished - upload Not FINISHED yet => REST at "+event.listing[idx].size,Debug.BLUE);
						
						bytesLoaded = event.listing[idx].size;
			
						// Dispatching upload progress
						var progressEvent:FTPEvent = new FTPEvent(FTPEvent.UPLOAD_PROGRESS);
						progressEvent.progress		= Math.round((100 * event.listing[idx].size) / (fileSize));
						progressEvent.bytes			= event.listing[idx].size;
						progressEvent.bytesTotal	= fileSize;
						progressEvent.startTime		= getTimer() - uploadStartTime;
						progressEvent.now			= getTimer();
						dispatchEvent(progressEvent);

						// continue uploading (REST mode)
						putFile(srcPath,destFolder+destName, event.listing[idx].size);
						
						// update state
						state = STATE_VIDEO_UPLOADING;
					}
					return;
				}
			}		
		}
		/**
		 * Cancel the upload
		 */
		override public function close():void
		{
			super.close();
			state = STATE_VIDEO_CANCEL;
		}
		/**
		 * complete the upload once metaData are set
		 */
		public function completeUpload(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - completeUpload ");
			
			// 
//			addEventListener(FTPEvent.CONNECTED,doLoginAfterConnectedAfterUpload);
			
			state = STATE_VIDEO_UPLOAD_SUCCESS;

			//disconnect
/*			if (ctrlSocket.connected)
				completeUploadAfterLogin();
			else
				// connect
				connect(host,port);
*/		}
		/**
		 * (re)start the login process
		 */
/*		private function doLoginAfterConnectedAfterUpload(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - doLoginAfterConnectedAfterUpload "+user);
			
			addEventListener(FTPEvent.LOGGED,completeUploadAfterLogin);
			login(user,pass);
		}
		/**
		 * complete the upload once metaData are set and connection is up (again)
		 * => upload the preview or directly the metaData
		 */
/*		public function completeUploadAfterLogin(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - completeUploadAfterLogin "+user);
			removeEventListener(FTPEvent.CONNECTED,doLoginAfterConnectedAfterUpload);
			removeEventListener(FTPEvent.LOGGED,completeUploadAfterLogin);
			
			// upload the preview or directly the metaData
			if(metaData.previewFileLocalPath && metaData.previewFileLocalPath!="")
			{
				//completeUploadByUploadingXMLForPreview();
				
				// no more xml for preview
				completeUploadByUploadingPreview();
			}
			else
			{
				// upload the metadata in an xml file
				completeUploadByUploadingMetaData();
			}
			
		}
*/
		/**
		 * upload an empty xml file for the preview
		 */
/* no more xml for preview		public function completeUploadByUploadingXMLForPreview(e:FTPEvent=null):void
		{
			// update state
			state = STATE_VIDEO_UPLOADING_PREVIEW;
			
			addEventListener(FTPEvent.UPLOAD,completeUploadByUploadingPreview);
			
			var previewFileXmlName:String = metaData.previewFileName.substring(0,metaData.previewFileName.lastIndexOf(".")) + ".xml";
			Debug.log("UploaderClient - completeUploadByUploadingXMLForPreview "+metaData.previewFileName + " -> "+previewFileXmlName);

			putEmptyFile(destFolder+previewFileXmlName);
		}
		/**
		 * upload the preview
		 */
/*		public function completeUploadByUploadingPreview(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - completeUploadByUploadingPreview "+e);

			removeEventListener(FTPEvent.UPLOAD,completeUploadByUploadingPreview);
			addEventListener(FTPEvent.UPLOAD,completeUploadPreview);
			
			// image has same name as the video
			var fileName:String = metaData.filename.substr(0,metaData.filename.lastIndexOf(".")) + ".img";
			putFile(metaData.previewFileLocalPath,destFolder+fileName);
			
			// now, image has same name as the video + .img putFile(metaData.previewFileLocalPath,destFolder+metaData.previewFileName);
		}
		/**
		 * preview successfully uploaded
		 */
/*		private function completeUploadPreview(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - completeUploadPreview "+e);
			removeEventListener(FTPEvent.UPLOAD,completeUploadPreview);
			completeUploadByUploadingMetaData();
		}
		/**
		 * handle error while creating the xml file containing the metaData before it is uploaded
		 */
/*		private function readWriteError(e:Error):void
		{
			Debug.error("UploaderClient readWriteError "+e);
		}
		/**
		 * upload the metadata in an xml file
		 */
/*		private function completeUploadByUploadingMetaData(e:FTPEvent=null):void
		{
			Debug.log("UploaderClient - completeUploadByUploadingMetaData ");
			// update state
			state = STATE_VIDEO_UPLOADING_XML;
						
			// Getting the reference to the XML file in the app storage
			var fileXML:File = File.applicationStorageDirectory.resolvePath(xmlFileName);
			
			// Delete the file if he already exists
			if (fileXML.exists) 
			{
				try 
				{
					fileXML.deleteFile();
				} 
				catch (e:IOError) 
				{
					readWriteError(e); 
					return;
				}
			}
			var fileStream:FileStream = new FileStream();
			// Writing it on the local storage app
			try {
				fileStream.open(fileXML, FileMode.WRITE);
				fileStream.writeUTFBytes(metaData.toXML());
			}
			catch (e:Error)		{ readWriteError(e); return; }
			catch (e:IOError)	{ readWriteError(e); return; }
		
			fileStream.close();
			//
			addEventListener(FTPEvent.UPLOAD,handlecompleteUploadFinished);
			putFile(fileXML.nativePath,destFolder+xmlFileName);
		}
		/**
		 * FINAL SUCCESS
		 */
/*		private function handlecompleteUploadFinished(event:FTPEvent):void
		{
			Debug.log("UploaderClient - handlecompleteUploadFinished FINAL SUCCESS",Debug.GREEN);
			state = STATE_VIDEO_UPLOAD_SUCCESS;
		}
*/	}
}